'''
第八周作业第一题，抓取豆瓣网中top250图书
时间：20180917
地址：https://book.douban.com/top250?start=0
'''

# 导入模块
from requests.exceptions import RequestException
from lxml import etree
from bs4 import BeautifulSoup
from pyquery import PyQuery as pq
import requests
import re,time,json,os

def getPage(url):
	'''
	爬取指定url页面信息
	@param string url
	'''
	try:
		#定义请求头信息
		headers = {
			'User-Agent':'User-Agent:Mozilla/5.0(WindowsNT6.1;rv:2.0.1)Gecko/20100101Firefox/4.0.1'
		}
		# 执行爬取
		res = requests.get(url,headers=headers)
		#判断响应状态,并响应爬取内容
		if res.status_code == 200:
			return res.text
		else:
			return None
	except RequestException:
		return None

def handleTitle(_str):
	'''
	标题处理函数
	@param string str
	@return string title
	'''
	title = _str
	title = title.replace("\n",'').replace("\r",'').replace("\t",'').replace('                                   ','');
	title = title.strip()

	return title

def parsePage(content,action):
	'''
	解析爬取网页中的内容，并返回字段结果
	@param string content
	@param string action
	'''
	if action == 'pq':
		# =========使用pyquery解析==================
		# 解析HTML文档
		doc = pq(content)
		#获取网页中所有标签并遍历输出标签名
		items = doc("tr.item")
		for item in items.items():
			title = handleTitle(item.find("div.pl2 a").text())
			yield {
				'image':item.find("a.nbg img").attr('src'),
				'title':title,
				'author':item.find("p.pl").text(),
				'comment':item.find("div.star span.pl").text(),
				'score':item.find("div.star span.rating_nums").text(),
			}
	elif action == 'bs':
		# ====================使用Beautiful Soup解析====================
		# 解析HTML文档
		soup = BeautifulSoup(content,"lxml")
		#获取网页中所有标签并遍历输出标签名
		items = soup.find_all(name="tr",attrs={"class":"item"})
		print(items)
		#遍历封装数据并返回
		for item in items:
			title = handleTitle(item.select("div.pl2 a")[0].get_text())
			yield {
				'image':item.find(name="img",attrs={'width':'90'}).attrs['src'],
				'title':title, #内有标签使用string获取不到
				'author':item.find(name="p",attrs={'class':'pl'}).string,
				'comment':item.find(name="span",attrs={'class':'pl'}).string,
				'score':item.find(name="span",attrs={'class':'rating_nums'}).string,
			}
	elif action == 'xpath':
		# =======使用xpath解析====================
		# 解析HTML文档，返回根节点对象
		html = etree.HTML(content)
		#获取网页中所有标签并遍历输出标签名
		items = html.xpath('//tr[@class="item"]')
		#遍历封装数据并返回
		for item in items:
			title = handleTitle(item.xpath('.//td[2]/div[@class="pl2"]/a/text()')[0])
			comment = handleTitle(item.xpath('.//td[2]/div[2]/span[3]/text()')[0])
			yield {
				'image':item.xpath('.//td[1]/a/img[@width="90"]/@src')[0],
				'title':title,
				'author':item.xpath('.//td[2]/p[@class="pl"]/text()')[0],
				# 'comment':item.xpath('.//td[2]/div[2]/span[3]/text()')[0],
				'comment':comment,
				'score':item.xpath('.//td[2]/div[2]/span[2]/text()')[0],
			}

def writeFile(content):
	'''
	执行文件追加写操作
	@param string content
	'''
	#print(content)
	with open("./result.txt",'a',encoding='utf-8') as f:
		f.write(json.dumps(content,ensure_ascii=False) + "\n")
		#json.dumps 序列化时对中文默认使用的ascii编码.想输出真正的中文需要指定ensure_ascii=False

def save_image_file(url, path):
	'''
	保存图书封面图片
	@param string url
	@param string path
	'''
	ir = requests.get(url)
	if ir.status_code == 200:
		with open(path, 'wb') as f:
			f.write(ir.content)
			f.close()

def main(offset,action):
	''' 主程序函数，负责调度执行爬虫处理 '''
	url = 'https://book.douban.com/top250?start='+str(offset)
	html = getPage(url)
	#判断是否爬取到数据，并调用解析函数
	if html:
		if not os.path.exists('images'):
			os.mkdir('images')

		for item in parsePage(html,action):
			print(item)
			writeFile(item)
			save_image_file(item['image'], './images/' + item['title'] + '.jpg')

# 判断当前执行是否为主程序运行，并遍历调用主函数爬取数据
if __name__ == '__main__':
	# main(0,'xpath')
	for i in range(10):
		offset=i*25
		main(offset,'xpath')
		time.sleep(1)